<template>
  <div class="table">
    <el-table
      ref="tableRef"
      border
      :data="dataSource"
      v-loading="loading"
      @sort-change="sortChange"
      @select="onSelect"
      @select-all="onSelect"
      @row-click="clickRow"
      @cell-click="clickCell"
      height="670"
      :row-style="{ height: 54 + 'px' }"
      :cell-style="{ padding: 0 + 'px' }"
      :show-summary="showSummary"
      :summary-method="summaryMethod"
      :sum-text="sumText"
      @expand-change="handleExpandChange"
    >
      <!-- 多选 -->
      <el-table-column v-if="selection" type="selection" width="55" fixed align="center" />
      <!-- 展开 -->
      <el-table-column v-if="expandKey" label="展开" fixed type="expand">
        <template #default="scope">
          <ExpandTable
            :columns="expandColumns"
            :data-source="scope.row[expandKey]"
            :loading="loading"
            :options="options"
          >
            <template #expandOperate="{ row }">
              <slot :row="row" name="expandOperate" />
            </template>
          </ExpandTable>
        </template>
      </el-table-column>
      <!-- 序号 -->
      <el-table-column
        v-if="index"
        type="index"
        :label="$t('lang.table.index')"
        fixed
        align="center"
        :index="handleIndex"
      />
      <column
        v-for="column of columns"
        :key="column.key"
        :item="column"
        :options="options"
        :fixed="column.fixed"
      />
      <!-- 操作列 -->
      <el-table-column
        v-if="$slots.operate"
        :label="$t('lang.operate.name')"
        fixed="right"
        :min-width="operateMinWidth"
        align="center"
      >
        <template #default="scope">
          <div class="operate">
            <slot :row="scope.row" name="operate" />
          </div>
        </template>
      </el-table-column>
    </el-table>
    <el-pagination
      class="pagination"
      v-if="pagination"
      v-model:current-page="pagination.pageNum"
      :page-size="pagination.pageSize"
      :page-sizes="pageSizes"
      layout="sizes, total, prev, pager, next, jumper"
      :total="pagination.total"
      background
      @current-change="changePage"
      @size-change="handleSizeChange"
      style="margin: 10px 0 0 0"
    />
  </div>
</template>
<script lang="ts">
import { defineComponent, PropType, ref, watch, nextTick, onMounted, computed } from 'vue'
import { DataSource, Columns, Pagination } from './types'
import Column from './Column.vue'
import { ObjectType } from 'typings/interfaces'
import { Options } from '../Form/types'
import { Optional } from 'typings/util'
import { intersectionBy, forEach, differenceBy } from 'lodash'
import { useStore } from 'vuex'
import { useRouter } from 'vue-router'
import ExpandTable from '@/components/Records/ExpandTable.vue'

export * from './types'

type Sort = Optional<Pagination>

interface Order {
  order: 'ascending' | 'descending' | null
  prop: string
}

export default defineComponent({
  emits: {
    'change-page': null,
    'update:selectedRows': null,
    'size-change': null,
    'expand-change': null,
  },
  components: {
    Column,
    ExpandTable,
  },
  props: {
    loading: {
      type: Boolean,
      required: true,
    },
    columns: {
      type: Array as PropType<Columns>,
      required: true,
    },
    dataSource: {
      type: Array as PropType<DataSource>,
      required: true,
    },
    pagination: {
      type: Object as PropType<Pagination>,
      required: true,
    },
    // 非必填
    index: {
      type: Boolean,
      default: true,
    },
    selection: {
      type: Boolean,
      default: true,
    },
    selectedRows: {
      type: Array as PropType<ObjectType[]>,
      default: [],
    },
    defaultSelectedRows: {
      type: Array as PropType<ObjectType[]>,
      default: [],
    },
    options: {
      type: Object as PropType<Options>,
      default: () => ({}),
    },
    maxHeight: {
      type: Number,
      default: 500,
    },
    valuePath: {
      type: String,
      default: 'id',
    },
    sort: {
      type: Function as PropType<(obj: Sort) => Promise<ObjectType[]>>,
      required: true,
    },
    showSummary: {
      type: Boolean,
      default: false,
    },
    summaryMethod: {
      type: Function as PropType<(obj: ObjectType) => Promise<any[]>>,
      default: null,
    },
    sumText: {
      type: String,
      default: '合计',
    },
    sizeChange: {
      type: Function as PropType<(obj: ObjectType) => Promise<any[]>>,
      default: null,
    },
    expandKey: {
      type: String,
      default: null,
    },
    expandColumns: {
      type: Array,
      default: () => [],
    },
    operateMinWidth: {
      type: String || Number,
      default: 200,
    },
  },
  setup(props, { emit }) {
    const store = useStore()
    const router = useRouter()
    const tableRef = ref<ObjectType | null>(null)
    const toggleSelection = (selectedRows: ObjectType[], toggleStatus: boolean) =>
      forEach(selectedRows, (row) => tableRef?.value?.toggleRowSelection(row, toggleStatus))

    // 初始已选择行
    onMounted(() =>
      toggleSelection(intersectionBy(props.dataSource, props.selectedRows, props.valuePath), true)
    )
    // 监听数据发生变化
    watch(
      () => props.dataSource,
      () =>
        nextTick().then(() =>
          toggleSelection(
            intersectionBy(props.dataSource, props.selectedRows, props.valuePath),
            true
          )
        )
    )

    // 选择项发生变化
    watch(
      () => props.selectedRows,
      () =>
        toggleSelection(differenceBy(props.dataSource, props.selectedRows, props.valuePath), false)
    )

    // 多选,选择行
    const onSelect = (rows: ObjectType[]) => {
      const initRows = differenceBy(
        props.selectedRows,
        intersectionBy(props.dataSource, props.selectedRows, props.valuePath),
        props.valuePath
      )
      emit('update:selectedRows', [...initRows, ...rows])
    }
    /* 排序 */
    const sortChange = ({ order, prop }: Order) => {
      const types: Record<string, 'ASC' | 'DESC'> = {
        ascending: 'ASC',
        descending: 'DESC',
      }
      if (order && prop == 'statusName') {
        props.sort({ orderType: types[order], orderBy: 'status' })
      } else if (order) {
        props.sort({ orderType: types[order], orderBy: prop })
      }
    }
    const handleIndex = (index: number) => {
      const { pageNum, pageSize } = props.pagination
      return (pageNum - 1) * pageSize + index + 1
    }

    const pageSizes = computed(() => store.state.global.pageSizes)
    const handleSizeChange = (val: number) => {
      store.commit('savePageSize', val)
      emit('size-change', val)
    }
    const serviceFacility = {
      tollGateNumber: 3,
      serviceAreaNum: 4,
      parkingArea: 5,
      gasStation: 6,
    }
    const clickCell = (row, column) => {
      if (
        (column.property == 'approvedBudget' && column.label == '投资规模(亿元)') ||
        (column.property == 'tollMile' && column.label == '收费里程') ||
        (column.property == 'maintenanceMileage' && column.label == '养护里程')
      ) {
        router.push({
          name: `路段`,
          params: { item: row.sectionAbbr },
        })
      }
      if (column.label == '总数(座)' && column.property == 'total') {
        router.push({
          name: `桥梁`,
          params: { item: row.sectionId },
        })
      }
      if (column.label == '总数(座)' && column.property == 'tunnelNum') {
        router.push({
          name: `隧道`,
          params: { item: row.sectionId },
        })
      }
      if (
        column.property == 'tollGateNumber' ||
        column.property == 'serviceAreaNum' ||
        column.property == 'parkingArea' ||
        column.property == 'gasStation'
      ) {
        router.push({
          name: `房建`,
          params: {
            item: row.sectionId,
            facilitiesType: serviceFacility[column.property],
          },
        })
      }
    }

    const handleExpandChange = (row, expandedRows) => {
      emit('expand-change', row, expandedRows)
    }

    return {
      tableRef,
      onSelect,
      clickCell,
      sortChange,
      changePage: (page: number) => emit('change-page', page),
      clickRow: (row: ObjectType) => props.selection || emit('update:selectedRows', [row]),
      handleIndex,
      handleSizeChange,
      pageSizes,
      handleExpandChange,
    }
  },
})
</script>
<style scoped lang="scss">
.table {
  display: flex;
  flex-direction: column;
  height: 100%;
  flex: 1;
  :global(.el-pagination) {
    text-align: end;
  }
  .pagination {
    margin-top: auto;
  }
}
::v-deep .el-table__body-wrapper {
  .el-table__expanded-cell {
    z-index: 100;
    padding: 0;
  }
}
::v-deep .el-table__fixed,
::v-deep .el-table__fixed-right {
  .el-table__expanded-cell {
    visibility: hidden;
    padding: 0;
  }
}
</style>
